This is one page of the R Handbook for Epidemiologists, but is being printed as a stand-alone page.

You can find the complete handbook on Github

Interactive plots

Data visualisation is increasingly required to be interrogable by the audience. Consequently creating interactive plots are becoming common. There are several ways to include these but the two most important are {plotly} and {shiny}.

{Shiny} is covered in another part of this handbook, so we will only cover {plotly} here. #TODO - link to shiny page

Overview

Making plots interactive can sound more difficult than it turns out to be, thanks to some fantastic tools.

In this section, you’ll learn to easily make a plot interactive with {the wonders {ggplot2} and {plotly}

Preparation

In the example you saw a very basic epicurve that had been transformed to bbe interactive using the fantastic {ggplot2} - {plotly} integrations. So to start, make a basic chart of your own:

Loading data

linelist <- rio::import("linelist_cleaned.xlsx")

Manipulate and add columns (best taught in the epicurves section)

linelist <- linelist %>% 
  dplyr::mutate(
    ## If the outcome column is NA, change to "Unknown"
    outcome = dplyr::if_else(condition = is.na(outcome),
                             true = "Unknown",
                             false = outcome),
    ## If the date of infection is NA, use the date of onset instead
    date_earliest = dplyr::if_else(condition = is.na(date_infection),
                                   true = date_onset,
                                   false = date_infection),
    ## Summarise earliest date to earliest week 
    week_earliest = lubridate::floor_date(x = date_earliest,
                                          unit = "week",
                                          week_start = 1)
    )

Count for plotting

## Find number of cases in each week by their outcome
linelist <- linelist %>% 
  dplyr::count(week_earliest, outcome)

Plot

Make into a plot

p <- linelist %>% 
  ggplot()+
  geom_col(aes(week_earliest, n, fill = outcome))+
  xlab("Week of infection/onset") + ylab("Cases per week")+
  theme_minimal()

Make interactive

p <- p %>% 
  plotly::ggplotly()

Voila!

p

Modifications

When exporting in an Rmarkdown generated HTML (like this book!) you want to make the plot as small as possible (with no negative side effects in most cases). For this, just add add this line:

p <- p %>% 
  plotly::partial_bundle()

Some of the buttons on a standard plotly (as shown on the preparation tab) are superfluous and can be distracting, so it’s best to remove them. You can do this simply by piping the output into plotly::config

## these buttons are superfluous/distracting
plotly_buttons_remove <- list('zoom2d','pan2d','lasso2d', 'select2d','zoomIn2d',
                              'zoomOut2d','autoScale2d','hoverClosestCartesian',
                              'toggleSpikelines','hoverCompareCartesian')

p <- p %>% 
  plotly::config(displaylogo = FALSE, modeBarButtonsToRemove = plotly_buttons_remove)

Example

Earlier you saw #TODO link to heatmaps how to make heatmaps, and they are just as easy to make interactive.

metrics_plot %>% 
  ggplotly() %>% 
  partial_bundle() %>% 
  config(displaylogo = FALSE, modeBarButtonsToRemove = plotly_buttons_remove)

Maps - preparation

You can even make interactive maps! However, they’re slightly trickier. Although {plotly} works well with ggplot2::geom_sf in RStudio, when you try to include it’s outputs in Rmarkdown HTML files (like this book), it doesn’t work well.

So instead you can use {plotly}’s own mapping tools which can be tricky but are easy when you know how. Read on…

We’re going to use Covid-19 incidence across African countries for this example. The data used can be found on the World Health Organisation website.

You’ll also need a new type of file, a GeoJSON, which is sort of similar to a shp file for those familiar with GIS. For this book, we used one from here.

GeoJSON files are stored in R as complex lists and you’ll need to maipulate them a little.

## You need two new packages: {rjson} and {purrr}
pacman::p_load(plotly, rjson, purrr)

## This is a simplified version of the WHO data
df <- rio::import(here::here("data", "covid_incidence.csv"))

## Load your geojson file
geoJSON <- rjson::fromJSON(file=here::here("data", "africa_countries.geo.json"))

## Here are some of the properties for each element of the object
head(geoJSON$features[[1]]$properties)
## $scalerank
## [1] 1
## 
## $featurecla
## [1] "Admin-0 country"
## 
## $labelrank
## [1] 6
## 
## $sovereignt
## [1] "Burundi"
## 
## $sov_a3
## [1] "BDI"
## 
## $adm0_dif
## [1] 0

This is the tricky part. For {plotly} to match your incidence data to GeoJSON, the countries in the geoJSON need an id in a specific place in the list of lists. For this we need to build a basic function:

## The property column we need to choose here is "sovereignt" as it is the names for each country
give_id <- function(x){
  
  x$id <- x$properties$sovereignt  ## Take sovereignt from properties and set it as the id
  
  return(x)
}

## Use {purrr} to apply this function to every element of the features list of the geoJSON object
geoJSON$features <- purrr::map(.x = geoJSON$features, give_id)

Maps - plot

plotly::plot_ly() %>% 
  plotly::add_trace(                    #The main plot mapping functionn
    type="choropleth",
    geojson=geoJSON,
    locations=df$Name,          #The column with the names (must match id)
    z=df$Cumulative_incidence,  #The column with the incidence values
    zmin=0,
    zmax=57008,
    colorscale="Viridis",
    marker=list(line=list(width=0))
  ) %>%
  plotly::colorbar(title = "Cases per million") %>%
  plotly::layout(title = "Covid-19 cumulative incidence",
                 geo = list(scope = 'africa')) %>% 
  plotly::config(displaylogo = FALSE, modeBarButtonsToRemove = plotly_buttons_remove)

Resources

Plotly is not just for R, but also works well with Python (and really any data science language as it’s built in JavaScript). You can read more about it on the plotly website